#
# rakesh sugirtharaj
# adaptive binary boosting
# machine learning
# graded assignment # 2-a
#


#! /usr/bin/perl


use strict;
use warnings;

my @hypotheses;
my $best_hypothesis = {};

my $error = 1;
my $zt = 0;
my $alpha = 0;
my $r = 0;
my $w = 0;

my @x;
my @y;
my @meta;
my @p;

&read_input("data-ex.txt");
&initialize;

my $i = 1;
while($meta[0] != 0){
	&find_best_hypothesis;

	&recalculate_probabilities;
	&print_iteration($i);
	$i++;
	$meta[0]--;
}

sub read_input{
	open FILE, "<", $_[0] or die $!;
	print "Reading from input file : " . $_[0] . "\n";
	my $i = 1;
	while(<FILE>){
		my @a = split(/ /,$_);
		if($i == 1){
			@meta = @a;
		}elsif($i == 2){
			@x = @a;
		}elsif($i == 3){
			@y = @a;
		}else{
			@p = @a;
		}
		$i++;
	}
	
	close(FILE);
}

sub initialize{
	foreach my $i (0..($#x + 1)){
		$hypotheses[$i] = {"name" => "< " . &getname_for_lt($i)};
	}
	
	foreach my $i ($#x + 2..(2*$#x)+3){
		$hypotheses[$i] = {"name" => "> " . &getname_for_gt($i)};
	}
	
}

sub find_best_hypothesis{
	$error = 1;
	foreach(@hypotheses){
		&find_error($_);
		if($_->{"error"} < $error){
			$error = $_->{"error"};
			$best_hypothesis = $_;
		}
	}
}

sub recalculate_probabilities{
	$zt = 0;
	$alpha = 0;
	if($best_hypothesis->{"error"} != 0){
		$alpha = (0.5) * log((1-$best_hypothesis->{"error"})/$best_hypothesis->{"error"});
	}
	$r = exp(-1 * $alpha);
	$w = exp($alpha);
	
	foreach my $j(0 .. $#p){
		if($best_hypothesis->{"wrongs"}->{$j}){
			$p[$j] = $p[$j] * $w;
		}else{
			$p[$j] = $p[$j] * $r;
		}
	}

	foreach(@p){
		$zt = $zt + $_;
	}

	foreach my $k (0 .. $#p){
		$p[$k] = $p[$k]/$zt;
	}
}

sub print_iteration{
	open OUTPUT, ">>output-bin.txt" or die $!;
	print OUTPUT "Iteration " . $_[0] . "\n";
	print OUTPUT "Chosen hypothesis : " . $best_hypothesis->{"name"} . "\n";
	print OUTPUT "Error of this hypothesis : " . $best_hypothesis->{"error"} . "\n";
	print OUTPUT "alpha : " . $alpha . "\n";
	#print OUTPUT "wrong : " . $w . "\n";
	#print OUTPUT "right : " . $r . "\n";
	print OUTPUT "Zt : " . $zt . "\n";
	print OUTPUT "Updated probabilities (Normalized) : \n";
	foreach(@p){
		print OUTPUT $_ . " ";
	}
	print OUTPUT "\n\n\n";
	close(OUTPUT);
}

sub find_error{
	my @temp = split(/ /, $_->{"name"});
	my $err = 0;
	$_->{"wrongs"} = ();
	
	if($temp[0] eq "<"){
		foreach my $i (0 .. $#x){
			if($x[$i] < $temp[1]){
				if($y[$i] == -1){
					$err = $err + $p[$i];
					$_->{"wrongs"}->{$i} = 1;
				}
			}else{
				if($y[$i] == 1){
					$err = $err + $p[$i];
					$_->{"wrongs"}->{$i} = 1;
				}
			}
		}
	}

	if($temp[0] eq ">"){
		for my $i (0 .. $#x){
			if($x[$i] > $temp[1]){
				if($y[$i] == -1){
					$err = $err + $p[$i];
					$_->{"wrongs"}->{$i} = 1;
				}
			}else{
				if($y[$i] == 1){
					$err = $err + $p[$i];
					$_->{"wrongs"}->{$i} = 1;
				}
			}
		}
	}
	$_->{"error"} = $err;
	
}
sub getname_for_lt{
	if($_[0] == 0){
		return $x[$_[0]] - 1;
	}elsif($_[0] == $#x + 1){
		return $x[$_[0] -1] + 1;
	}else{
		return ($x[$_[0]] + $x[$_[0] - 1])/2;
	}
}


sub getname_for_gt{
	my $k = $_[0] - $#x - 2;
	if($k == 0){
		return $x[$k] - 1;
	}elsif($k == $#x + 1){
		return $x[$k - 1] + 1;
	}else{
		return ($x[$k] + $x[$k-1])/2;
	}
}
